from flask import request, jsonify, send_file, current_app, g, Response
from flask_jwt_extended import jwt_required
import os
import uuid
import datetime
import io
import base64
from bson import ObjectId
from werkzeug.utils import secure_filename
import mimetypes

from app.api.v1 import api_bp
from app import mongo
from app.utils.auth import permission_required
from app.utils.common import paginate, allowed_file, normalize_data

@api_bp.route('/files/upload', methods=['POST'])
@jwt_required()
@permission_required('file:upload')
def upload_file():
    """上传文件（图片或文本）"""
    # 检查是否有文件
    if 'file' not in request.files:
        return jsonify({
            'success': False,
            'message': '没有提供文件'
        }), 400
    
    file = request.files['file']
    if file.filename == '':
        return jsonify({
            'success': False,
            'message': '没有选择文件'
        }), 400
    
    # 检查文件类型是否允许
    if not allowed_file(file.filename):
        return jsonify({
            'success': False,
            'message': '不支持的文件类型'
        }), 400
    
    # 安全处理文件名
    filename = secure_filename(file.filename)
    original_name = filename
    
    # 确定文件类型
    ext = filename.rsplit('.', 1)[1].lower() if '.' in filename else ''
    content_type = file.content_type
    
    # 判断是图片还是文本
    file_type = 'image' if content_type.startswith('image/') else 'document'
    
    # 只接受图片和文本文件
    if file_type != 'image' and file_type != 'document':
        return jsonify({
            'success': False,
            'message': '只支持图片和文本文件'
        }), 400
    
    # 读取文件内容
    file_content = file.read()
    
    # 对于图片文件，将二进制转为base64以便前端直接显示
    if file_type == 'image':
        file_base64 = base64.b64encode(file_content).decode('utf-8')
        data_url = f"data:{content_type};base64,{file_base64}"
    else:
        # 对于文本文件，尝试解码为文本
        try:
            data_url = file_content.decode('utf-8')
        except UnicodeDecodeError:
            data_url = base64.b64encode(file_content).decode('utf-8')
    
    # 准备文件信息
    file_info = {
        'filename': original_name,
        'contentType': content_type,
        'size': len(file_content),
        'type': file_type,
        'data': data_url,
        'relatedId': request.form.get('relatedId'),
        'relatedType': request.form.get('relatedType'),
        'description': request.form.get('description', ''),
        'uploadBy': str(g.current_user['_id']),
        'uploadByName': g.current_user.get('name', ''),
        'createdAt': datetime.datetime.utcnow(),
        'updatedAt': datetime.datetime.utcnow()
    }
    
    # 保存到数据库
    result = mongo.db.files.insert_one(file_info)
    
    return jsonify({
        'success': True,
        'message': '文件上传成功',
        'data': {
            'id': str(result.inserted_id),
            'filename': original_name,
            'contentType': content_type,
            'type': file_type,
            'size': file_info['size'],
            'createdAt': file_info['createdAt'].isoformat()
        }
    }), 201

@api_bp.route('/files', methods=['GET'])
@jwt_required()
@permission_required('file:read')
def get_files():
    """获取文件列表"""
    # 获取查询参数
    page = request.args.get('page', 1, type=int)
    limit = request.args.get('limit', 20, type=int)
    sort_by = request.args.get('sortBy', 'createdAt')
    order = request.args.get('order', 'desc')
    include_data = request.args.get('includeData', 'false').lower() == 'true'
    
    # 构建查询条件
    query = {}
    
    # 按关联ID筛选
    related_id = request.args.get('relatedId')
    if related_id:
        query['relatedId'] = related_id
    
    # 按关联类型筛选
    related_type = request.args.get('relatedType')
    if related_type:
        query['relatedType'] = related_type
    
    # 按文件类型筛选
    file_type = request.args.get('type')
    if file_type:
        query['type'] = file_type
    
    # 确定排序
    sort_direction = -1 if order.lower() == 'desc' else 1
    
    # 查询数据库
    files_cursor = mongo.db.files.find(query).sort(sort_by, sort_direction)
    
    # 分页
    paginated_data = paginate(files_cursor, page, limit)
    
    # 标准化数据
    files = []
    for file in paginated_data['items']:
        file_data = normalize_data(file)
        # 默认不包含实际数据内容，除非特别请求
        if not include_data:
            file_data.pop('data', None)
        files.append(file_data)
    
    return jsonify({
        'success': True,
        'data': {
            'total': paginated_data['total'],
            'page': paginated_data['page'],
            'limit': paginated_data['per_page'],
            'files': files
        }
    }), 200

@api_bp.route('/files/<id>', methods=['GET'])
@jwt_required()
@permission_required('file:read')
def get_file(id):
    """获取文件详情"""
    # 查询文件
    file = None
    if ObjectId.is_valid(id):
        file = mongo.db.files.find_one({'_id': ObjectId(id)})
    
    if not file:
        return jsonify({
            'success': False,
            'message': '文件不存在'
        }), 404
    
    # 标准化数据
    file_data = normalize_data(file)
    
    # 如果不需要实际文件内容，则移除data字段
    include_data = request.args.get('includeData', 'true').lower() == 'true'
    if not include_data:
        file_data.pop('data', None)
    
    return jsonify({
        'success': True,
        'data': file_data
    }), 200

@api_bp.route('/files/data/<id>', methods=['GET'])
@jwt_required()
@permission_required('file:read')
def get_file_data(id):
    """获取文件数据"""
    # 查询文件
    file = None
    if ObjectId.is_valid(id):
        file = mongo.db.files.find_one({'_id': ObjectId(id)})
    
    if not file:
        return jsonify({
            'success': False,
            'message': '文件不存在'
        }), 404
    
    if 'data' not in file:
        return jsonify({
            'success': False,
            'message': '文件数据不存在'
        }), 404
    
    # 如果是图片，data已经是base64格式，可以直接在<img>标签中使用
    # 如果是文本，data就是文本内容
    
    # 确定内容类型（图片或文本）
    content_type = file.get('contentType', 'application/octet-stream')
    
    # 如果前端需要直接展示图片，可以使用如下方式返回
    # <img src="/api/v1/files/data/xxxx">
    if content_type.startswith('image/'):
        # 处理base64数据
        if file['data'].startswith('data:'):
            # 已经是data URL格式，直接返回
            image_data = file['data']
        else:
            # 只有base64字符串，添加data URL前缀
            image_data = f"data:{content_type};base64,{file['data']}"
        
        # 返回data URL格式的图片数据
        return Response(
            image_data,
            mimetype='text/plain'  # 返回为纯文本，让前端决定如何使用
        )
    else:
        # 返回文本数据
        return Response(
            file['data'],
            mimetype=content_type
        )

@api_bp.route('/files/<id>', methods=['DELETE'])
@jwt_required()
@permission_required('file:delete')
def delete_file(id):
    """删除文件"""
    # 查询文件
    file = None
    if ObjectId.is_valid(id):
        file = mongo.db.files.find_one({'_id': ObjectId(id)})
    
    if not file:
        return jsonify({
            'success': False,
            'message': '文件不存在'
        }), 404
    
    # 删除数据库记录
    mongo.db.files.delete_one({'_id': ObjectId(id)})
    
    return jsonify({
        'success': True,
        'message': '文件删除成功',
        'data': None
    }), 200 